package semantic_matching.entity_search.entity_tree;

import common.dao.elastic.ElasticSearchDao;
import common.dao.orient.OrientGraphDao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import query_understanding.query_language.doc_entity_tree.EntityQueryTree;
import query_understanding.query_language.doc_entity_tree.QueryEdge;
import query_understanding.query_language.doc_entity_tree.QueryNode;
import query_understanding.query_understand.tree_progress.EntityQueryProgress;
import semantic_matching.common.schema.MatchedEntites;
import semantic_matching.common.schema.MatchedEntityTree;

import java.util.Map;


/**
 * Created by julianzliu on 4/25/2017.
 */
public class EntityQueryMatcher {

    static final Logger logger = LoggerFactory.getLogger(EntityQueryMatcher.class);

    private ElasticSearchDao searchDao;
    private OrientGraphDao orientGraphDao;
    //private OrientGraph orientGraph;

    private QueryEdgeSolver queryEdgeSolver;
    private QueryNodeSolver queryNodeSolver;


    public EntityQueryMatcher(ElasticSearchDao searchDao, OrientGraphDao orientGraphDao){
        this.searchDao = searchDao;
        this.orientGraphDao = orientGraphDao;
        this.queryNodeSolver = new QueryNodeSolver();
        this.queryEdgeSolver = new QueryEdgeSolver(this.searchDao, this.orientGraphDao);
    }





    public MatchedEntityTree matchEntityQueryTree(EntityQueryTree tree){

        EntityQueryProgress.deepFirstTraversal( tree );


        /*
        保存每个节点和关系的结果
         */
        MatchedEntityTree matchedEntityTree = new MatchedEntityTree();
        matchedEntityTree.entityTree = tree;
        Map<QueryEdge.BaseEdge, MatchedEntites> edgesEntities = matchedEntityTree.edgesEntities;
        Map<QueryNode.BaseNode, MatchedEntites> nodesEntities = matchedEntityTree.nodesEntities;

        QueryNode.BaseNode root = tree.answerEntity;
        EntityQueryQueue queryQueue = new EntityQueryQueue(tree, matchedEntityTree);



        while ( root.solved == false){
            logger.info("[MatchedEntityTree] in while loop . SolvableNodeSize = {}, SolvableEdgeSize = {} ", queryQueue.getSolvableNodeSize(), queryQueue.getSolvableEdgeSize() );

            if(queryQueue.getSolvableNodeSize() == 0 && queryQueue.getSolvableEdgeSize() == 0){
                System.out.println("\n\n\n\n\n ERROR \n\n\n\n\n");
                break;
            }

            // 1) 处理所有可解节点
            while (queryQueue.getSolvableNodeSize() > 0){
                // solve a node
                QueryNode.BaseNode node = queryQueue.selectNode();
                solveNode( node, nodesEntities,edgesEntities  );
                queryQueue.solvedNode(node);
                logger.info("[Solved A Node {}]\n\n", node.hashCode());
            }

            // 2） 直到没有可解的 节点， 再求解边
            if( queryQueue.getSolvableEdgeSize() > 0){
                // solve a edge
                QueryEdge.BaseEdge edge = queryQueue.selectEdge();
                solveEdge( edge, edgesEntities, nodesEntities );
                queryQueue.solvedEdge(edge);
                logger.info("[Solved A Edge {}]\n\n", edge.hashCode());
            }

        }

        MatchedEntites rootEntities = nodesEntities.get(root);
        matchedEntityTree.rootEntities = rootEntities;
        logger.info( "[rootEntitiesSize] = {}", rootEntities.entities.size() );
        return matchedEntityTree;
    }


    /***************************************************************
     *
     * @param node
     */
    // 求解一个节点
    private void solveNode(QueryNode.BaseNode node,Map<QueryNode.BaseNode, MatchedEntites> nodesEntities, Map<QueryEdge.BaseEdge, MatchedEntites> edgesEntities ){
        this.queryNodeSolver.solveNode(node, nodesEntities, edgesEntities);
    }


    /****************************************************************
     *
     * @param edge
     */
    // 求解一个关系
    private void solveEdge(QueryEdge.BaseEdge edge, Map<QueryEdge.BaseEdge, MatchedEntites> edgesEntities,Map<QueryNode.BaseNode, MatchedEntites> nodesEntities){
        this.queryEdgeSolver.solveEdge(edge, edgesEntities, nodesEntities);
    }



    /********************************************************************
     *
     */
    public static void main(String[] args){

    }
}
